package com.zl.zsk.config.security;

import com.zl.zsk.pojo.SysUser;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * @author lxb
 * @version 1.0.0
 * @desc:
 * @date 2020-03-16 9:41
 */
@Component
public class JwtProvider {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtProvider.class);
    @Value("${jwt.secret}")
    private String jwtSecret;
    @Value("${jwt.expiration}")
    private int jwtExpiration;
    @Value("${jwt.expired.time}")
    private long expiredInRedisTime;


    /**
     * 生成jwt信息
     *
     * @param authentication
     * @return
     */
    public String generateJwtToken(Authentication authentication) {
        SysUser user = (SysUser) authentication.getPrincipal();
        Date nowDate = new Date();
        Date expiredDate = new Date((nowDate).getTime() + jwtExpiration * 1000);
        String jwt = Jwts.builder()
                .setSubject(user.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(expiredDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
        LOGGER.info("生成的jwt信息：{}", jwt);

        return jwt;
    }

    /**
     * 验证签名
     *
     * @param token
     * @return
     */
    public boolean validateJwtToken(String token) {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
        return true;
//            final String name = getUsernameFromToken(token);
//            return name.equals(username)&&!isTokenExpired(token);
//            return true;
//        }catch (SignatureException e){
//            LOGGER.error("签名不正确 -> Message:{}",e);
//        }catch (MalformedJwtException e){
//            LOGGER.error("鉴权信息token不正确 -> Message:{}",e);
//        }catch (ExpiredJwtException e){
//            LOGGER.error("鉴权信息已过期 -> Message:{}",e);
//        }catch (UnsupportedJwtException e){
//            LOGGER.error("不支持的token鉴权 -> Message:{}",e);
//        }catch (IllegalArgumentException e){
//            LOGGER.error("鉴权中的声明信息为空 -> Message:{}",e);
//        }
//        return false;
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    private String doGenerateToken(Map<String, Object> claims, String subject) {

        return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + jwtExpiration * 1000))
                .signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
    }

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return doGenerateToken(claims, username);
    }

    /**
     * 解析jwt获取里面的用户信息，即用户名
     *
     * @param token
     * @return
     */
    public String getUserNameFromJwtToken(String token) {
        return Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
    }

    public Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

}
